use std::cell::Cell;
use std::io;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Mutex;

use actix_web::{App, get, HttpRequest, HttpResponse, HttpServer, middleware, Responder, web};

#[get("/{id}/{name}/index.html")]
async fn index(web::Path((id, name)): web::Path<(u32, String)>) -> impl Responder {
    format!("Hello {}! id:{}", name, id)
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {

    // Create some global state prior to building the server
    // #[allow(clippy::mutex_atomic)] // it's intentional.
    let counter1 = web::Data::new(Mutex::new(0usize));
    let counter3 = web::Data::new(AtomicUsize::new(0usize));

    HttpServer::new(move || {
        // Create some thread-local state
        let counter2 = Cell::new(0u32);

        App::new()
            .app_data(counter1.clone()) // add shared state
            .app_data(counter3.clone()) // add shared state
            .data(counter2) // add thread-local state
            .service(index)
            //.route("/", web::get().to(simple_index))
            .service(web::resource("/").to(simple_index))
    })
        .bind("127.0.0.1:8080")?
        .run()
        .await
}

async fn simple_index(
    counter1: web::Data<Mutex<usize>>,
    counter2: web::Data<Cell<u32>>,
    counter3: web::Data<AtomicUsize>,
    req: HttpRequest,
) -> HttpResponse {
    println!("{:?}", req);

    // Increment the counters
    *counter1.lock().unwrap() += 1;
    counter2.set(counter2.get() + 1);
    counter3.fetch_add(1, Ordering::SeqCst);

    let body = format!(
        "global mutex counter: {}, local counter: {}, global atomic counter: {}",
        *counter1.lock().unwrap(),
        counter2.get(),
        counter3.load(Ordering::SeqCst),
    );
    HttpResponse::Ok().body(body)
}